
/*
 * Copyright (C) 2008-2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: CursorStateTest3.java 377 2010-03-11 20:50:18Z archie.cobbs $
 */

package org.dellroad.sidekar.util;

import com.sleepycat.je.DatabaseEntry;

import java.util.ArrayList;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotSame;
import static org.testng.Assert.assertTrue;

public class CursorStateTest3 extends CursorStateTest {

    @Test
    public void checkSeek1() {

        // Pick a random value in the database
        final BDB bdb = getBDB();
        final DatabaseEntry entry = bdb.keyMap.keySet().iterator().next();

        // Check seeking to it
        CloseableNotes.performAction(new VoidDatabaseAction() {
            public void executeVoid() {

                // Seek to it exactly
                CursorState cursorState = new CursorState(bdb.db.openCursor(env.getCurrentTransaction(), null));
                boolean found = cursorState.seek(entry, null, true);
                assertTrue(found);
                assertEquals(cursorState.getCurrentKey(), entry);

                // Seek to it again inexactly
                found = cursorState.seek(entry, null, false);
                assertTrue(found);
                assertEquals(cursorState.getCurrentKey(), entry);

                // Seek to it again exactly
                found = cursorState.seek(entry, null, true);
                assertTrue(found);
                assertEquals(cursorState.getCurrentKey(), entry);

                // Advance cursor past it
                if (cursorState.forward())
                    assertNotSame(cursorState.getCurrentKey(), entry);
            }
        });
    }

    @Test(dataProvider = "data")
    public void checkSeekRandom(Integer startKey, Integer stopKey, final int seekTo, final boolean exact, final Integer result) {
        DatabaseEntry temp = null;
        if (startKey != null) {
            temp = new DatabaseEntry();
            getEntry(temp, startKey);
        }
        final DatabaseEntry startEntry = temp;
        if (stopKey != null) {
            temp = new DatabaseEntry();
            getEntry(temp, stopKey);
        }
        final DatabaseEntry stopEntry = temp;
        final BDB bdb = getBDB();
        CloseableNotes.performAction(new VoidDatabaseAction() {
            public void executeVoid() {
                CursorState cursorState = new CursorState(bdb.db.openCursor(env.getCurrentTransaction(), null),
                  startEntry, stopEntry);
                DatabaseEntry keyEntry = new DatabaseEntry();
                getEntry(keyEntry, seekTo);
                boolean found = cursorState.seek(keyEntry, null, exact);
                if (result == null)
                    assertFalse(found);
                else {
                    assertTrue(found);
                    assertTrue(cursorState.isActive());
                    assertEquals(cursorState.getCurrentKey().getData()[0] & 0xff, result.intValue());
                }
            }
        });
    }

    @DataProvider(name = "data")
    public Object[][] genTestCases() {
        ArrayList<Object[]> list = new ArrayList<Object[]>();
        for (int i = 0; i < 200; i++) {
            Integer startKey = null;
            Integer stopKey = null;
            if (this.random.nextBoolean()) {
                startKey = 90 + random.nextInt(110);
                stopKey = 90 + random.nextInt(110);
            }
            int seekTo = 90 + random.nextInt(110);
            boolean exact = random.nextBoolean();
            Integer result;
            int temp = seekTo;
            if (!exact) {
                if (startKey != null && temp < startKey)
                    temp = startKey;
                if (temp < 100)
                    temp = 100;
            }
            if (!exact && (temp % 10) != 0)
                temp += 10 - (temp % 10);
            if ((startKey != null && temp < startKey)
              || (stopKey != null && temp >= stopKey)
              || temp < 100 || temp > 190
              || (temp % 10) != 0)
                result = null;
            else
                result = temp;
            list.add(new Object[] { startKey, stopKey, seekTo, exact, result });
        }
        return list.toArray(new Object[list.size()][]);
    }

    @Override
    protected int getNumEntries(String name) {
        return 10;
    }

    @Override
    protected void createEntry(String name, int i, DatabaseEntry key, DatabaseEntry value) {
        getEntry(key, 100 + i * 10);
        getEntry(value, i);
    }

    private void getEntry(DatabaseEntry entry, int i) {
        entry.setData(new byte[] { (byte)i });
    }
}

